refactor: migrate to RemoteOAuthStorage for web OAuth handling#1609
refactor: migrate to RemoteOAuthStorage for web OAuth handling#1609BobDickinson wants to merge 3 commits into
Conversation
|
@claude review |
|
Claude finished @BobDickinson's task in 3m 21s —— View job Code Review — PR #1609 (migrate web OAuth to
|
PR review response — async OAuth storage / callback raceRe: review feedback on The latest commit ( 1. Callback reads PKCE before persisted state is loaded
2. Writes can clobber
|
|
@claude review |
|
Claude finished @BobDickinson's task in 2m 57s —— View job Re-review after the
|
PR comment — settle
|
|
@claude review |
|
Claude finished @BobDickinson's task in 2m 6s —— View job Re-review after
|
|
Regarding the "eager rejection" recommendation - that entire class of problem goes away with the removal of Zustand storage, which will be a fast follow. I'm happy to go with what we have now so we can get to that work. |
Closes #1548
Summary
Wire the v2 web client through shared file-backed OAuth storage instead of tab-local
sessionStorage.RemoteOAuthStorage→GET/POST /api/storage/oauth→~/.mcp-inspector/storage/oauth.json(same on-disk file as CLI/TUI when using the default local backend).getWebRemoteOAuthStorage()(clients/web/src/lib/remoteOAuthStorage.ts) memoizes one in-memoryRemoteOAuthStorageper{ origin, authToken }so connect, EMA IdP session, and per-server “clear stored OAuth” all mutate the same Zustand view.core/unchanged — no Zustand removal, no async storage interface churn (Remove Zustand file-store wrappers; auto-convert to plain JSON on read #1549 / Web: migrate auth store to shared /store API (RemoteOAuthStorage parity with TUI/CLI) #1592-style work stays out of scope).Why
BrowserOAuthStorage→sessionStorage(tab-local)RemoteOAuthStorage→oauth.json(shared with CLI/TUI)getBrowserOAuthStorage)getWebRemoteOAuthStorage) over remote adapterCall chain
authTokenis forwarded on storage HTTP calls asx-mcp-remote-authwhen the backend requires it (same as transport/fetch/logger).Changes
New
clients/web/src/lib/remoteOAuthStorage.tsgetRemoteOAuthStorage/getWebRemoteOAuthStorageclients/web/src/lib/remoteOAuthStorage.test.tsclients/web/src/lib/environmentFactory.test.tsModified (web)
clients/web/src/lib/environmentFactory.tsgetWebRemoteOAuthStorage(authToken)instead ofgetBrowserOAuthStorage(); doc commentclients/web/src/App.tsxwebOAuthStorageuseMemo; EMA + clear OAuth use shared store; callback commentclients/web/src/utils/clearServerOAuthState.tsoauthStorage: OAuthStorage; active client narrowed toPick<InspectorClient, "clearOAuthTokens">clients/web/vite.config.tssrc/lib/**to coverageincludeTests / coverage
clearServerOAuthState.test.tsBrowserOAuthStorageinstances; typed client stub (noas never)storage-browser.test.tsgetBrowserOAuthStoragesingleton branch (coverage for core helper still used elsewhere)Spec
specification/v2_auth_ema.mdoauth.json; mark #1548 follow-up donespecification/v2_auth_mid_session.mdOut of scope (follow-ups)
navigator.locks— Cross-tab single-flight on silent refresh (noted in spec).Review notes
RemoteOAuthStorageinstance owns a separate in-memory Zustand store; memoization matches the oldgetBrowserOAuthStorage()pattern.clearServerOAuthStateplumbsoauthStoragefromAppso unit tests stay isolated without stubbingwindow/remote fetch; parameter types narrowed to what the helper actually calls.useMemo([], getAuthToken())matches existingsessionStorageAdapterassumption: API token is stable for the page lifetime (injected__INSPECTOR_API_TOKEN__on load).